<?php

namespace unifiedpay\plugins;
use Exception;

require_once dirname(__FILE__)."/vendor/autoload.php";

class Alipay
{
	static public $info = [
		'name' => 'alipay',
		'sort' => 1,
		'link' => 'https://b.alipay.com/signing/productSetV2.htm',
		'types' => ['alipay'],
	];

	public $channel;
	private $settings;
	public function __construct() {
		global $_G;
		$this->settings = $this->getConfig();
		$this->settings['notify_url'] = $_G['siteurl'] . 'api/payment/notify/notify_alipay.php';
	}

	private function getConfig() {
		$settings = \C::t('common_setting')->fetch_setting('unifiedpay_alipay', true);
		if($settings['cert_mode'] == 1){
			$settings['app_cert'] = DISCUZ_ROOT.$settings['app_cert'];
			$settings['alipay_cert'] = DISCUZ_ROOT.$settings['alipay_cert'];
			$settings['root_cert'] = DISCUZ_ROOT.$settings['root_cert'];
		}
		return $settings;
	}

	public function pay($order) {
		global $_G;
		\C::t('common_payment_order')->update($order['id'], array('channel' => 'alipay', 'plugin' => 'alipay'));
		if (defined('IN_MOBILE') && in_array('2', $this->settings['product'])) {
			return $this->alipay_trade_wap_pay($order);
		} elseif(!defined('IN_MOBILE') && in_array('1', $this->settings['product'])) {
			return $this->alipay_trade_page_pay($order);
		} elseif(in_array('3', $this->settings['product'])) {
			return $this->alipay_trade_qr_pay($order);
		} elseif(!defined('IN_MOBILE') && in_array('2', $this->settings['product'])) {
			$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=alipay';
			return array('code' => 200, 'type' => 'qrcode', 'url' => $pay_url);
		} elseif(in_array('4', $this->settings['product'])) {
			if (strpos($_SERVER['HTTP_USER_AGENT'], 'AlipayClient/')!==false) {
				return $this->alipay_trade_app_pay_h5($order);
			} else {
				$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=alipay';
				return array('code' => 200, 'type' => 'qrcode', 'url' => $pay_url);
			}
		}
		return array('code' => 500, 'message' => 'Did not open payment');
	}

	//APP支付
	public function pay_apppay($order) {
		global $_G;
		if (in_array('4', $this->settings['product'])) {
			return $this->alipay_trade_app_pay($order);
		} else {
			$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=alipay';
			return array('code' => 200, 'type' => 'jump', 'url' => $pay_url);
		}
	}

	//小程序支付
	public function pay_miniapp($order, $code) {
		global $_G;
		try{
			$oauth = new \Alipay\AlipayOauthService($this->settings);
			$result = $oauth->getToken($code);
			if(!empty($result['user_id'])){
				$openid = $result['user_id'];
				$openid_type = 'userid';
			}else{
				$openid = $result['open_id'];
				$openid_type = 'openid';
			}
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}

		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'out_trade_no' => $order['out_biz_no'],
			'total_amount' => sprintf('%.2f', $order['amount'] / 100),
			'subject' => $order['subject'],
			'body' => $order['description'],
		];
		if(in_array('5', $this->settings['product'])){
			$bizContent['product_code'] = 'JSAPI_PAY';
			$bizContent['op_app_id'] = $this->settings['app_id'];
		}
		if($openid_type == 'userid'){
			$bizContent['buyer_id'] = $openid;
		}else{
			$bizContent['buyer_open_id'] = $openid;
		}
		if (filter_var($_G['clientip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
			$bizContent['business_params'] = ['mc_create_trade_ip' => $_G['clientip']];
		}
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$result = $aop->jsPay($bizContent);
			return array('code' => 200, 'type' => 'qrcode', 'url' => $result);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	private function alipay_trade_page_pay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'out_trade_no' => $order['out_biz_no'],
			'total_amount' => sprintf('%.2f', $order['amount'] / 100),
			'subject' => $order['subject'],
			'body' => $order['description'],
			'qr_pay_mode' => '2',
		];
		if (filter_var($_G['clientip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
			$bizContent['business_params'] = ['mc_create_trade_ip' => $_G['clientip']];
		}
		$this->settings['return_url'] = $order['return_url'];
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$html_text = $aop->pagePay($bizContent);
			return array('code' => 200, 'type' => 'html', 'url' => $html_text);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	private function alipay_trade_wap_pay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'out_trade_no' => $order['out_biz_no'],
			'total_amount' => sprintf('%.2f', $order['amount'] / 100),
			'subject' => $order['subject'],
			'body' => $order['description'],
		];
		if (filter_var($_G['clientip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
			$bizContent['business_params'] = ['mc_create_trade_ip' => $_G['clientip']];
		}
		$this->settings['return_url'] = $order['return_url'];
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$html_text = $aop->wapPay($bizContent);
			return array('code' => 200, 'type' => 'html', 'url' => $html_text);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	private function alipay_trade_qr_pay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'out_trade_no' => $order['out_biz_no'],
			'total_amount' => sprintf('%.2f', $order['amount'] / 100),
			'subject' => $order['subject'],
			'body' => $order['description'],
		];
		if (filter_var($_G['clientip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
			$bizContent['business_params'] = ['mc_create_trade_ip' => $_G['clientip']];
		}
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$result = $aop->qrPay($bizContent);
			$pay_url = $result['qr_code'];
			return array('code' => 200, 'type' => 'qrcode', 'url' => $pay_url);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	private function alipay_trade_app_pay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'out_trade_no' => $order['out_biz_no'],
			'total_amount' => sprintf('%.2f', $order['amount'] / 100),
			'subject' => $order['subject'],
			'body' => $order['description'],
		];
		if (filter_var($_G['clientip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
			$bizContent['business_params'] = ['mc_create_trade_ip' => $_G['clientip']];
		}
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$result = $aop->appPay($bizContent);
			return array('code' => 200, 'type' => 'sdk', 'url' => $result);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	private function alipay_trade_app_pay_h5($order) {
		$result = $this->alipay_trade_app_pay($order);
		if ($result['code'] == 200) {
			$jump_url = 'alipays://platformapi/startApp?appId=20000125&orderSuffix='.urlencode($result['url']).'#Intent;scheme=alipays;package=com.eg.android.AlipayGphone;end';
			return array('code' => 200, 'type' => 'jump', 'url' => $jump_url);
		}else{
			return $result;
		}
	}

	public function status($out_biz_no) {
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$res = $aop->query(null, $out_biz_no);
			if($res['trade_status'] == 'TRADE_SUCCESS') {
				return array('code' => 200, 'data' => array('trade_no' => $res['trade_no'], 'payment_time' => strtotime($res['send_pay_date'])));
			} else {
				return array('code' => 500, 'message' => $res['trade_status']);
			}
		}catch(Exception $e){
			return array('code' => 501, 'message' => $e->getMessage());
		}
	}

	public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
		}

		$bizContent = [
			'trade_no' => $trade_no,
			'refund_amount' => sprintf('%.2f', $refund_amount / 100),
			'out_request_no' => $refund_no
		];
		if($refund_desc) $bizContent['refund_reason'] = $refund_desc;
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$result = $aop->refund($bizContent);
			return array('code' => 200, 'data' => array('refund_time' => time()));
		}catch(Exception $e){
			return array('code' => 501, 'message' => $e->getMessage());
		}
	}

	public function refund_status($refund_no, $trade_no) {
		global $_G;

		$bizContent = [
			'trade_no' => $trade_no,
			'out_request_no' => $refund_no
		];
		try{
			$aop = new \Alipay\AlipayTradeService($this->settings);
			$result = $aop->refundQuery($bizContent);
			return array('code' => 200, 'data' => array('refund_time' => time()));
		}catch(Exception $e){
			return array('code' => 501, 'message' => $e->getMessage());
		}
	}

	public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$title = diconv($title, $_G['charset'], 'UTF-8');
			$desc = diconv($desc, $_G['charset'], 'UTF-8');
		}

		if(is_numeric($account) && substr($account,0,4)=='2088' && strlen($account)==16)$is_userid = true;
		else $is_userid = false;
		
		$money = sprintf('%.2f', $amount / 100);
		try{
			$transfer = new \Alipay\AlipayTransferService($this->settings);
			$result = $transfer->transferToAccount($transfer_no, $money, $is_userid, $account, $realname, $title);
			return array('code' => 200, 'data' => array('transfer_time' => strtotime($result['trans_date'])));
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	public function transfer_status($transfer_no) {
		global $_G;

		try{
			$transfer = new \Alipay\AlipayTransferService($this->settings);
			$result = $transfer->query($transfer_no, 2);
			if($result['status'] == 'SUCCESS') {
				return array('code' => 200, 'data' => array('transfer_time' => strtotime($result['trans_date'])));
			} elseif($result['status'] == 'DEALING') {
				return array('code' => 201, 'message' => 'DEALING');
			} else {
				return array('code' => 500, 'message' => $result['status']);
			}
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	public function notify() {
		if(!$_POST['sign'] || !$_POST['sign_type']) {
			exit('fail');
		}
		
		$aop = new \Alipay\AlipayTradeService($this->settings);
		$verify_result = $aop->check($_POST);
		if(!$verify_result) {
			exit('fail');
		}
		
		if($_POST['trade_status'] == 'TRADE_SUCCESS') {
			$out_biz_no = $_POST['out_trade_no'];
			
			unifiedpay_process_notify($out_biz_no, $_POST['trade_no'], $_POST['buyer_id']);
			exit('success');
		}
		
		exit('fail');
	}

	public function oauth() {
		global $_G;
		$oauth = new \Alipay\AlipayOauthService($this->settings);
		if(isset($_GET['auth_code'])){
			try{
				$result = $oauth->getToken($_GET['auth_code']);
				$user_id = $result['user_id'];
				return array('code' => 200, 'data' => $user_id);
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}else{
			$redirect_uri = $_G['siteurl'].'plugin.php?id=unifiedpay:openid';
			$oauth->oauth($redirect_uri);
		}
	}
}